import time
from typing import List, Union, cast

import pydantic
from fastapi import Depends, Request
from sqlalchemy import delete, insert, select, update

from forward.api.admin.config import AdminConfig
from forward.api.admin.schemas.system import (
    SystemAuthMenuCreateInSchema,
    SystemAuthMenuEditInSchema,
    SystemAuthMenuOutSchema,
    SystemAuthMenuSchema,
)
from forward.dependencies.database import db
from forward.model.tables import SystemAuthMenuModel
from forward.utils.array import ArrayUtil
from forward.utils.redis import RedisUtil
from forward.api.admin.service.system.auth_perm import SystemAuthPermService


class SystemAuthMenuService:
    """系统菜单服务实现类"""

    def __init__(self, request: Request, auth_perm_service: SystemAuthPermService):
        self.request: Request = request
        self.auth_perm_service: SystemAuthPermService = auth_perm_service

    async def select_menu_by_role_id(self, role_ids: List[int]):
        """根据角色ID获取菜单"""
        admin_id = self.request.state.admin_id
        menu_ids = await self.auth_perm_service.select_menu_ids_by_role_id(
            role_ids
        ) or [0]
        where = [
            SystemAuthMenuModel.menu_type.in_(("M", "C")),
            SystemAuthMenuModel.is_disable == 0,
        ]
        if admin_id != 1:
            where.append(SystemAuthMenuModel.id.in_(menu_ids))
        menus = await db.fetch_all(
            select(SystemAuthMenuModel)
            .where(*where)
            .order_by(SystemAuthMenuModel.menu_sort.desc(), SystemAuthMenuModel.id)
        )
        menu_list = [
            SystemAuthMenuSchema.model_validate(menu, from_attributes=True).model_dump(
                by_alias=True
            )
            for menu in menus
        ]
        return ArrayUtil.list_to_tree(
            menu_list,
            "id",
            "pid",
            "children",
        )

    async def list(self):
        """菜单列表"""
        menus = await db.fetch_all(
            select(SystemAuthMenuModel).order_by(
                SystemAuthMenuModel.menu_sort.desc(), SystemAuthMenuModel.id
            )
        )
        menu_list = [
            SystemAuthMenuSchema.model_validate(menu, from_attributes=True).model_dump(
                by_alias=True
            )
            for menu in menus
        ]
        return ArrayUtil.list_to_tree(
            menu_list,
            "id",
            "pid",
            "children",
        )

    async def detail(self, id_: int) -> Union[SystemAuthMenuOutSchema, dict]:
        """菜单详情"""
        menu = await db.fetch_one(
            select(SystemAuthMenuModel).where(SystemAuthMenuModel.id == id_).limit(1)
        )
        assert menu, "菜单已不存在!"
        return SystemAuthMenuOutSchema.model_validate(
            menu, from_attributes=True
        ).model_dump(exclude_none=True, by_alias=True)

    async def add(self, create_in: SystemAuthMenuCreateInSchema):
        """新增菜单"""
        create_dict = create_in.model_dump()

        await db.execute(insert(SystemAuthMenuModel).values(**create_dict))
        await RedisUtil.delete(AdminConfig.backstage_roles_key)

    async def edit(self, edit_in: SystemAuthMenuEditInSchema):
        """编辑菜单"""
        assert await db.fetch_one(
            select(SystemAuthMenuModel).where(SystemAuthMenuModel.id == edit_in.id)
        ), "菜单已不存在!"
        edit_dict = edit_in.model_dump()
        await db.execute(
            update(SystemAuthMenuModel)
            .where(SystemAuthMenuModel.id == edit_in.id)
            .values(**edit_dict)
        )
        await RedisUtil.delete(AdminConfig.backstage_roles_key)

    async def delete(self, id_: int):
        """删除菜单"""
        assert await db.fetch_one(
            select(SystemAuthMenuModel).where(SystemAuthMenuModel.id == id_).limit(1)
        ), "菜单已不存在!"
        assert not await db.fetch_one(
            select(SystemAuthMenuModel).where(SystemAuthMenuModel.pid == id_)
        ), "请先删除子菜单再操作！"
        await db.execute(
            delete(SystemAuthMenuModel).where(SystemAuthMenuModel.id == id_)
        )
        await self.auth_perm_service.batch_delete_by_menu_id(id_)
        await RedisUtil.delete(AdminConfig.backstage_roles_key)

    @classmethod
    async def instance(
        cls,
        request: Request,
        auth_perm_service: SystemAuthPermService = Depends(
            SystemAuthPermService.instance
        ),
    ):
        """实例化"""
        return cls(request, auth_perm_service)
